/**
 * AGNModelGeometry.java
 */

package agngui.agnmodel;
import java.util.ArrayList;
import java.util.List;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.PickInfo;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
    
/**
 * Defines the geometry present in the AGN model and implicitly constructs
 * the proper branch graphs for Java3D
 */
public class AGNModelGeometry {
	/**
	 * The disk's identifier
	 */
    public static final String EMISSIONDISK      = "Emission Disk";
    
    /**
     * The cone's identifier
     */
    public static final String SCATTERCONE       = "Cone";
    
    /**
     * The identifier for the cone when the countercone is showing
     */
    public static final String SCATTERCONEPAIR   = "Cone Pair";
    
    /**
     * The torus identifier
     */
    public static final String SCATTERTORUS      = "Torus"; 
    
    /**
     * The equatorial region's identifier
     */
    public static final String SCATTEREQUATORIAL = "Equatorial";
    
    /**
     * The wind region identifier
     */
    public static final String SCATTERWIND       = "Wind";
    

    /**
     * The branch group base for the entire system
     */
    private BranchGroup     system            = null;
    
    /**
     * The transform group that defines the transform for which the entire system
     * is subjected
     */
    private TransformGroup  systemTransform   = null;

    /**
     * the list of objects being rendered
     */
    private List<AGNObject> objectList       = null;
    
    /**
     * AGNModelGeometry
     *
     * Initializes the geometry (creates an empty set)
     */
    public AGNModelGeometry() {
        system            = new BranchGroup();
        systemTransform   = new TransformGroup();

        //systemTransform.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE );
        //systemTransform.setCapability( TransformGroup.ALLOW_TRANSFORM_READ  );        

        // system.addChild( systemTransform );

        objectList = new ArrayList<AGNObject>();
    }

    /**
     * addObject
     *
     * Adds an object to the model geometry. Will compile the associated BranchObject
     * if it is not already compiled. 
     *
     * @param object One of the supported model object types.
     */
    public void addObject( AGNObject object ) {
        system.addChild( object.getTransformGroup() );
		objectList.add( object );
    }

    /**
     * setInclinationAngle
     * 
     * Sets the inclination angle for the system relative to the y-axis
     * 
     * @param theta The inclination angle (degrees) about the x-axis in the ZY plane    
     */
    public void setInclinationAngle( double theta ) {
        Transform3D rotation  = new Transform3D();
        AxisAngle4d axisAngle;
        Vector3d    azimuth;

        // Convert theta to radians
        theta *= (Math.PI / 180);

        azimuth   = new Vector3d( 1, 0, 0 );
        axisAngle = new AxisAngle4d( azimuth, theta );
        rotation.setRotation( axisAngle );

        systemTransform.setTransform( rotation );
    }


    /**
     * getSystem
     * 
     * @return UNCOMPILED system branch group.
     */
    public BranchGroup getSystem() {
        return system;
    }

    /**
     * pickObject
     * 
     * Picks an object from the scene based on mouse coordinates.
     *
     * @param renderer The rendering object responsible for drawing the scene.
     * @param mX       The mouse click X coordinate
     * @param mY       The mouse click Y coordinate
     * @return A reference to the object picked by the mouse click.
     */
    public AGNObject pickObject( AGNModelRenderer renderer, int mX, int mY ) {
        PickInfo infoArray[] = system.pickAllSorted( PickInfo.PICK_GEOMETRY,
                                                     PickInfo.NODE,
                                                     renderer.getClickRay( mX, mY ) );
        AGNObject retVal = null;

        if( infoArray != null ) {
            retVal = (AGNObject)infoArray[0].getNode(); 
        }
        
        return retVal;
    }

    /**
     * pickObjectPoint
     *
     * Picks an object from the scene based on mouse coordinates and gets
     * the information about the ray-object intersection.
     *
     * @param renderer The rendering object responsible for drawing the scene.
     * @param mX       The mouse click X coordinate
     * @param mY       The mouse click Y coordinate
     * @return the point at which the ray intersected the picked object
     */
    public Point3d pickObjectPoint( AGNModelRenderer renderer, int mX, int mY ) {
        Point3d  retVal      = null;
        PickInfo infoArray[] = system.pickAllSorted( PickInfo.PICK_GEOMETRY,
                                                     PickInfo.NODE,
                                                     renderer.getClickRay( mX, mY ) );

        if( infoArray != null ) {
            retVal = infoArray[0].getIntersectionInfos()[0].getIntersectionPoint();
        }

        return retVal;
    } 

    /**
     * getSystemTransformGroup
     *
     * @return the system transform group for the model geometry
     */
    public TransformGroup getSystemTransformGroup() {
        return systemTransform;
    }

    /**
     * regenerateAllHandles
     *
     * Recalculates all geometry handles with the exception of the emission disk
     */
    public void regenerateAllHandles() {
        for( AGNObject object : objectList ) {
            if( object.getIdentifier() != EMISSIONDISK ) {
                object.generateHandles();
            }
        }
    }

}
